package Group9.TodoManager;

import Group9.TodoManager.Actions.AddAction;
import Group9.TodoManager.View.TodoManagerGUI;
import Group9.TodoManager.Data.SimpleTableModel;
import Group9.TodoManager.Controller.ITaskController;
import Group9.TodoManager.Data.Task;
import Group9.TodoManager.DataStore.Repository;
import Group9.TodoManager.View.AboutView;
import Group9.TodoManager.View.TaskUI;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * This class is used for storing the application settings that we are
 * currently employing. This class is a concrete class. This class configures
 * our application.
 * @author Rupesh
 * @author volkan cambazoglu
 */
public class Settings {

    private static Locale locale = Locale.getDefault();
    private static ResourceBundle languageResourceBundle;
    private static TodoManagerGUI mainGUI;
    private static Repository repository;
    private static ITaskController<Task> controller;
    private static SimpleTableModel<Task> tableModel;
    private static Properties preference;
    private static ResourceBundle themeResourceBundle;
    private static String theme;

    /**
     * Getter method for theme of the application
     * @return theme theme of the application
     */
    public static String getTheme() {
		return theme;
	}

    /**
     * Setter method for the theme of the application
     * @param theme theme of the application
     */
	public static void setTheme(String theme) {
		Settings.theme = theme;
	}

	/**
     * Returns the instance of resource bundle
     * @return This resource bundle is used for theme of the application
     */
    public static ResourceBundle getThemeResourceBundle() {
        if (themeResourceBundle == null) {
        	themeResourceBundle = ResourceBundle.getBundle(
        			"Group9.TodoManager.Theme", locale);
        }
        return themeResourceBundle;
    }
    
    /**
     * This returns the preference class instance for the application
     * @return Preference instance to store/retrieve the preference.
     */
    public static Properties getPreference() {
        if(preference == null){
            try {
                preference = new Properties(); 
                preference.load(new FileInputStream(getPreferencePath()));
            } catch (IOException ex) {
                System.err.println("IOException while getting preferences!");
            }
        }
        return preference;
    }

    /**
     * This method is used to get path of the preferences of the application
     * @return prefPath path of the preference
     */
    public static String getPreferencePath() {
        return System.getProperty("user.home") + "/TODO-Group9";
    }

    /**
     * This method is used for storing preferences
     */
    public static void flushProperties(){
        try {
        	preference.store(new FileOutputStream(getPreferencePath()), "Window States");
        } catch (IOException ex) {
        	System.err.println("Could not store the preference!");
        }
    }

    /**
     * This method returns the reference to the repository instance
     * @return The reference to the repository
     */
    public static Repository getRepository() {
        return repository;
    }

    /**
     * This method sets the Repository for the application. This reference of 
     * repository is used throughout the application.
     * @param repository The repository handler for the application
     */
    public static void setRepository(Repository repo) {
        repository = repo;
    }

    /**
     * This creates the mainGUI object if its not created and stores the
     * GUI reference. If the GUI object is already created then it returns
     * the reference of the previously created GUI instance.
     * @return mainGUI The instance of the main GUI.
     */
    public static TodoManagerGUI getMainGUI() {
        if(mainGUI == null) {
            mainGUI = new TodoManagerGUI(
                    getCurrentResourceBundle().getString("ApplicationTitle"),
                    getTaskController());

            mainGUI.addComponentListener(new ComponentListener() {

                /**
                 * When component is resized this method is executed
                 */
                public void componentResized(ComponentEvent e) {
                    Component c = (Component)e.getSource();

                    preference.put("WindowHeight",
                            Integer.toString(c.getHeight()));
                    preference.put("WindowWidth",
                            Integer.toString(c.getWidth()));
                }

                /**
                 * When component is moved this method is executed
                 */
                public void componentMoved(ComponentEvent e) {
                    Component c = (Component)e.getSource();
                    preference.put("WindowPositionX",
                            Double.toString(c.getLocation().getX()));
                    preference.put("WindowPositionY",
                            Double.toString(c.getLocation().getY()));
                }

                /**
                 * When component is shown, this method is executed.
                 */
                public void componentShown(ComponentEvent e) {

                }

                /**
                 * When component is hidden, this method is executed.
                 */
                public void componentHidden(ComponentEvent e) {

                }
            });
        }
        return mainGUI;
    }

    /**
     * This returns the view for creating a new task
     * @return taskUI The instance of add new task view instance
     */
    public static TaskUI getCreateTaskUI(Task task) {
        TaskUI taskUI = new TaskUI(task);
        taskUI.setSubmitAction(new AddAction<Task>(
        		Settings.getCurrentResourceBundle().getString("Submit"), null, 
        		Settings.getCurrentResourceBundle().getString("CreateAction"),
                                getTableModel(), taskUI, getRepository()));
        return taskUI;
    }

    /**
     * This method sets the locale for the application
     * @param language The language of the locale
     * @param country The country of the locale
     */
    public static void setLocale(String language, String country) {
        locale = new Locale(language, country);
        languageResourceBundle = null;
    }

    /**
     * Returns the default locale which is the locale of the OS
     * @return defaultLocale Returns the default locale instance
     */
    public static Locale getDefaultLocale() {
        return Locale.getDefault();
    }

    /**
     * Returns an instance of the model used to render the main UI
     * Here is the location where we specify the type of model like
     * specifying the type for the generic
     * @return tableModel returns an instance of the model used to render UI
     */
    public static SimpleTableModel<Task> getTableModel() {
        if(tableModel == null) {
            tableModel = new SimpleTableModel<Task>();
            tableModel.addColumns(
                    new String[] {
                Settings.getCurrentResourceBundle().getString("Title"),
                Settings.getCurrentResourceBundle().getString("Status"),
                Settings.getCurrentResourceBundle().getString("Category"),
                Settings.getCurrentResourceBundle().getString("Priority"),
                Settings.getCurrentResourceBundle().getString("BeginDate"),
                Settings.getCurrentResourceBundle().getString("EndDate")},
                new String[]{"Title", "Status",
            "Category","Priority","BeginDate","EndDate"})
            ;
        }
        return tableModel;
    }

    /**
     * Returns the instance of resource bundle
     * @return languageResourceBundle This resource bundle is used for 
     * internationalization
     */
    public static ResourceBundle getCurrentResourceBundle() {
        if(languageResourceBundle == null) {
            languageResourceBundle = ResourceBundle.getBundle(
            			"Group9.TodoManager.Language", locale);
        }
        return languageResourceBundle;
    }

    /**
     * This method is the getter of task controller
     * @return controller the controller to manage tasks
     */
    public static ITaskController<Task> getTaskController() {
        if(controller == null) {
            controller = new ITaskController<Task>(getTableModel(), getRepository());
        }
        return controller;
    }

    /**
     * Returns the language resource bundle for default locale
     * @return resourceBundle It returns the default language resource bundle
     */
    public static ResourceBundle getDefaultResourceBundle() {
        return ResourceBundle.getBundle("Group9.TodoManager.Language", getDefaultLocale());
    }

    /**
     * It returns the resource bundle for the specified locale
     * @param loc The locale of which we need the resource bundle
     * @return resourceBundle returns the resource bundle for the parameterized locale
     */
    public static ResourceBundle getResourceBundle(Locale loc) {
        return ResourceBundle.getBundle("Group9.TodoManager.Language", loc);
    }

    /**
     * This method is called to show the default not implemented message.
     */
    public static void showNotImplementedMessage() {
        displayMessage(mainGUI,
        Settings.getCurrentResourceBundle().getString("Message.NotImplemented"));
    }

    /**
     * This method shows the specified message in dialog with the main gui set
     * as parent so the dialog is shown as modal.
     * @param message The message to display
     */
    public static void displayMessage(String message) {
        displayMessage(mainGUI, message);
    }

    /**
     * This shows the message in dialog box with parent window set as provided
     * in parameter
     * @param parent The window above which the message should be displayed
     * @param message The message to show
     */
    public static void displayMessage(Component parent, String message) {
        JOptionPane.showMessageDialog(parent, message);
    }

    /**
     * This method returns the point where a component with dimension d is
     * to be shown so that it is in the center of the screen. This method is
     * used to know about the position to display a form so that it's shown at
     * the center of the screen.
     * @param d The dimension of the component
     * @return returns the starting point for the component to set so that
     * the component is displayed at the center of the screen.
     */
    public static Point getCenterPosition(Dimension d) {

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenSize = toolkit.getScreenSize();

        int x = (screenSize.width) / 2;
        int y = (screenSize.height) / 2;

        return new Point(x - (int) d.getWidth() / 2, y - (int) d.getHeight() / 2);
    }

    /**
     * This method shows the specified panel in a dialog box at the center of
     * the screen with the main GUI set as it's parent.
     * @param frame
     */
    public static void showDialog(JPanel frame) {
        JDialog dialog = new JDialog(getMainGUI());

        try {
        	((TaskUI) frame).setParentWindow(dialog);
        }
        catch(Exception e ) {
        	((AboutView) frame).setParentWindow(dialog);
        }

        dialog.setLocation(getCenterPosition(frame.getSize()));
        dialog.setContentPane(frame);
        dialog.setModal(true);
        dialog.setSize(frame.getWidth() + 6, frame.getHeight() + 28);
        dialog.setResizable(false);
        dialog.setVisible(true);

        dialog.dispose();
    }

    /**
     * This method shows the about screen of the application
     * @return aboutView the view that gives about information
     */
    public static JPanel getAboutTaskUI() {
        return new AboutView();
    }
}